package com.aliyun.heiyu.powermaster.server.dao.impl;

import com.aliyun.heiyu.common.util.*;
import com.aliyun.heiyu.powermaster.server.dao.entity.DataSign;
import com.aliyun.heiyu.powermaster.server.dao.StrategyActionDao;
import com.aliyun.heiyu.powermaster.server.dao.entity.StrategyActionEntity;
import com.google.gson.*;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

public class StrategyActionImpl implements StrategyActionDao {

    @Override
    public boolean insert(StrategyActionEntity entity) {
        entity = complex(entity);
        String sql = "insert into strategy_action(actionName,capTo,capType,fmin,state,minPower,maxPower," +
            "minCPUUsage,maxCPUUsage,startTime,endTime,strategyID) values(?,?,?,?,?,?,?,?,?,?,?,?)";
        Object[] kk = new Object[12];
        kk[0] = entity.getActionName();
        kk[1] = entity.getCapTo();
        kk[2] = entity.getCapType();
        kk[3] = entity.getFmin();
        kk[4] = entity.getState();
        kk[5] = entity.getMinPower();
        kk[6] = entity.getMaxPower();
        kk[7] = entity.getMinCPUUsage();
        kk[8] = entity.getMaxCPUUsage();
        kk[9] = entity.getStartTime();
        kk[10] = entity.getEndTime();
        kk[11] = entity.getStrategyID();
        boolean result = false;
        Integer insert = JdbcUtil.insert(sql, kk);
        if(insert != null && insert > 0){
            entity.setId(insert);
            result = insertBak(entity);
            //生成签名
            if(result){
                String sign = getSign(entity);
                result = insertSign(sign,"strategy_action",insert);
            }
        }
        return result;
    }

    public StrategyActionEntity findBakByID(Integer id) {
        String sql = "select * from strategy_action_bak where 1= ? and id=?";
        Integer[] kk = new Integer[2];
        kk[0] = 1;
        kk[1] = id;
        return JdbcUtil.queryForBean(sql,kk,StrategyActionEntity.class);
    }

    public String getSign(StrategyActionEntity entity){
        String s = toJsonString(entity);
        return SM3Util.convertEncryption(s);
    }

    public StrategyActionEntity isLegitimate(StrategyActionEntity entity){
        //验证是否被篡改
        String checkString = getSign(String.valueOf(entity.getId()));
        String checkString1 = getSign(entity);
        if(checkString == null){
            return entity;
        }
        if(checkString.equals(checkString1)){
            //解密
            return simplify(entity);
        }
        Integer id = entity.getId();
        StrategyActionEntity strategyActionEntityBak = findBakByID(id);
        boolean b = replace(strategyActionEntityBak);
        if(!b){
            return null;
        }
        //解密
        return simplify(strategyActionEntityBak);
    }

    public String toJsonString(StrategyActionEntity entity){
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        JsonParser jsonParser = new JsonParser();
        String s = gson.toJson(entity);
        JsonElement jsonElement = jsonParser.parse(s);
        sort(jsonElement);
        String s1 = gson.toJson(jsonElement);
        return s1;
    }

    private Comparator<String> getComparator() {
        return (s1, s2) -> s1.compareTo(s2);
    }

    /**
     * 排序
     *
     * @param e
     */
    public void sort(JsonElement e) {
        if (e.isJsonNull() || e.isJsonPrimitive()) {
            return;
        }

        if (e.isJsonArray()) {
            JsonArray a = e.getAsJsonArray();
            Iterator<JsonElement> it = a.iterator();
            it.forEachRemaining(i -> sort(i));
            return;
        }

        if (e.isJsonObject()) {
            Map<String, JsonElement> tm = new TreeMap<>(getComparator());
            for (Map.Entry<String, JsonElement> en : e.getAsJsonObject().entrySet()) {
                tm.put(en.getKey(), en.getValue());
            }

            String key;
            JsonElement val;
            for (Map.Entry<String, JsonElement> en : tm.entrySet()) {
                key = en.getKey();
                val = en.getValue();
                e.getAsJsonObject().remove(key);
                e.getAsJsonObject().add(key, val);
                sort(val);
            }
        }
    }

    public StrategyActionEntity simplify(StrategyActionEntity entity){
        Map<String, String> map = null;
        try {
            map = BeanUtils.describe(entity);
            Set<Map.Entry<String, String>> entries = map.entrySet();
            for(Map.Entry<String, String> entry : entries){
                String key = entry.getKey();
                String value = entry.getValue();
                //不加密主键id
                if(key.equals("id") || key.equals("strategyID")){
                    continue;
                }
                if(key.equals("class")){
                    continue;
                }
                if(StringUtil.isEmpty(value)){
                    continue;
                }
                map.put(key,simplify(value));
                BeanUtils.populate(entity,map);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return entity;
    }

    public StrategyActionEntity complex(StrategyActionEntity entity){
        Map<String, String> map = null;
        try {
            map = BeanUtils.describe(entity);
            Set<Map.Entry<String, String>> entries = map.entrySet();
            for(Map.Entry<String, String> entry : entries){
                String key = entry.getKey();
                String value = entry.getValue();
                //不加密主键id
                if(key.equals("id") || key.equals("strategyID")){
                    continue;
                }
                if(key.equals("class")){
                    continue;
                }
                if(StringUtil.isEmpty(value)){
                    continue;
                }
                map.put(key,complex(value));
                BeanUtils.populate(entity,map);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return entity;
    }

    public String complex(String param){
        param = SM4Util.encrypt_CBC2(param);
        return param;
    }

    public String simplify(String param){
        param = SM4Util.decrypt_CBC2(param);
        return param;
    }

    public boolean replace(StrategyActionEntity entity) {
        String sql = "update strategy_action set actionName=?,capTo=?,capType=?,fmin=?,state=?,minPower=?,maxPower=?," +
            "minCPUUsage=?,maxCPUUsage=?,startTime=?,endTime=?,strategyID=? where id=?";
        Object[] kk = new Object[13];
        kk[0] = entity.getActionName();
        kk[1] = entity.getCapTo();
        kk[2] = entity.getCapType();
        kk[3] = entity.getFmin();
        kk[4] = entity.getState();
        kk[5] = entity.getMinPower();
        kk[6] = entity.getMaxPower();
        kk[7] = entity.getMinCPUUsage();
        kk[8] = entity.getMaxCPUUsage();
        kk[9] = entity.getStartTime();
        kk[10] = entity.getEndTime();
        kk[11] = entity.getStrategyID();
        kk[12] = entity.getId();
        boolean result = JdbcUtil.update(sql, kk);
        return result;
    }

    public boolean insertBak(StrategyActionEntity entity) {
        String sql = "insert into strategy_action_bak(actionName,capTo,capType,fmin,state,minPower,maxPower," +
            "minCPUUsage,maxCPUUsage,startTime,endTime,strategyID,id) values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
        Object[] kk = new Object[13];
        kk[0] = entity.getActionName();
        kk[1] = entity.getCapTo();
        kk[2] = entity.getCapType();
        kk[3] = entity.getFmin();
        kk[4] = entity.getState();
        kk[5] = entity.getMinPower();
        kk[6] = entity.getMaxPower();
        kk[7] = entity.getMinCPUUsage();
        kk[8] = entity.getMaxCPUUsage();
        kk[9] = entity.getStartTime();
        kk[10] = entity.getEndTime();
        kk[11] = entity.getStrategyID();
        kk[12] = entity.getId();
        boolean result = JdbcUtil.update(sql, kk);
        return result;
    }

    public boolean insertSign(String sign, String schemaName, int id) {
        String sql = "insert into data_sign(schemaName,dataId,sign) values(?,?,?)";
        Object[] kk = new Object[3];
        kk[0] = schemaName;
        kk[1] = id;
        kk[2] = sign;
        boolean result = JdbcUtil.update(sql, kk);
        return result;
    }

    public String getSign(String dataId){
        String sql = "select *  from data_sign where dataId=? and schemaName=?";
        Object[] kk = new Object[2];
        kk[0] = dataId;
        kk[1] = "strategy_action";
        DataSign dataSign = JdbcUtil.queryForBean(sql, kk, DataSign.class);
        if(dataSign != null){
            return dataSign.getSign();
        }
        return null;
    }

    @Override
    public boolean update(StrategyActionEntity entity) {
        String sql = "update strategy_action set actionName=?,capTo=?,capType=?,fmin=?,state=?,minPower=?," +
            "maxPower=?,minCPUUsage=?,maxCPUUsage=?,startTime=?,endTime=?,strategyID=? where id=?";
        Object[] kk = new Object[13];
        kk[0] = entity.getActionName();
        kk[1] = entity.getCapTo();
        kk[2] = entity.getCapType();
        kk[3] = entity.getFmin();
        kk[4] = entity.getState();
        kk[5] = entity.getMinPower();
        kk[6] = entity.getMaxPower();
        kk[7] = entity.getMinCPUUsage();
        kk[8] = entity.getMaxCPUUsage();
        kk[9] = entity.getStartTime();
        kk[10] = entity.getEndTime();
        kk[11] = entity.getStrategyID();
        kk[12] = entity.getId();
        boolean result = JdbcUtil.update(sql, kk);
        return result;
    }

    @Override
    public boolean deleteByStrategyId(Integer strategyID) {
        String sql = "delete from strategy_action where strategyID=?";
        Integer[] kk = new Integer[1];
        kk[0] = strategyID;
        boolean result = JdbcUtil.update(sql, kk);
        return result;
    }

    @Override
    public List<StrategyActionEntity> findAll() {
        String sql = "select * from strategy_action";
        List<StrategyActionEntity> result = JdbcUtil.queryForList(sql, null, StrategyActionEntity.class);
        ArrayList<StrategyActionEntity> list = new ArrayList<>();
        if(result == null){
            return list;
        }
        for (StrategyActionEntity entity : result) {
            if(entity != null){
                list.add(isLegitimate(entity));
            }
        }
        return list;
    }

    @Override
    public boolean deleteByStrategyIDs(Object[] ids) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("delete from strategy_action");
        if (ids != null && ids.length != 0) {
            int length = ids.length;
            buffer.append(" where strategyID in (");
            for (int i = 0; i < length; i++) {
                if (i != length - 1) {
                    buffer.append("?,");
                } else {
                    buffer.append("?)");
                }
            }
        } else {
            return true;
        }
        return JdbcUtil.update(buffer.toString(),ids);
    }

    @Override
    public List<StrategyActionEntity> findByStrategyID(Integer strategyID) {
        String sql = "select * from strategy_action where strategyID=?";
        Integer[] kk = new Integer[1];
        kk[0] = strategyID;
        List<StrategyActionEntity> result = JdbcUtil.queryForList(sql, kk, StrategyActionEntity.class);
        ArrayList<StrategyActionEntity> list = new ArrayList<>();
        if(result == null){
            return list;
        }
        for (StrategyActionEntity entity : result) {
            if(entity != null){
                list.add(isLegitimate(entity));
            }
        }
        return list;
    }

}
